package es.service.impl;

import cn.hutool.core.lang.func.Func1;
import es.bean.CommonResult;
import es.bean.CompanyName;
import es.bean.ProcurementName;
import es.dto.BaseDto;
import es.dto.ProcurementDto;
import es.esmapper.CompanyMapper;
import es.esmapper.ProcurementMapper;
import es.esmapper.TenderSummaryMapper;
import es.po.TenderInfo;
import es.dao.TenderInfoMapper;
import es.service.TenderInfoService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import es.vo.ProcurementVo;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.dromara.easyes.core.conditions.select.LambdaEsQueryWrapper;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.script.Script;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.Aggregations;
import org.elasticsearch.search.aggregations.BucketOrder;
import org.elasticsearch.search.aggregations.PipelineAggregatorBuilders;
import org.elasticsearch.search.aggregations.bucket.terms.Terms;
import org.elasticsearch.search.aggregations.bucket.terms.TermsAggregationBuilder;
import org.elasticsearch.search.aggregations.metrics.Sum;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.io.IOException;
import java.text.DecimalFormat;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 中标数据 服务实现类
 * </p>
 *
 * @author mp
 * @since 2024-11-13
 */
@Slf4j
@Service
public class TenderInfoServiceImpl extends ServiceImpl<TenderInfoMapper, TenderInfo> implements TenderInfoService {

    @Resource
    private TenderInfoMapper tenderInfoMapper;
    @Resource
    private ProcurementMapper procurementMapper;
    @Resource
    private CompanyMapper companyMapper;
    @Resource
    private TenderSummaryMapper tenderSummaryMapper;

    @Override
    public CommonResult<Object> searchCompanyName(BaseDto dto) {
        long start = System.currentTimeMillis();
        LambdaEsQueryWrapper<CompanyName> queryWrapper = new LambdaEsQueryWrapper<>();
        //1-公司名称 2-法人名称
        if (dto.getSearchType() == 1){
            queryWrapper.match(CompanyName::getCompanyName,dto.getKey());
        }else if (dto.getSearchType() == 2){
            queryWrapper.match(CompanyName::getLegalName,dto.getKey());
        }else {
            return CommonResult.error("未知搜索类型");
        }
        queryWrapper.size(6).sortByScore();
//        queryWrapper.match(CompanyName::getLegalName,"雷军").size(6).csortByScore();
        List<CompanyName> companyNames = companyMapper.selectList(queryWrapper);
        long end = System.currentTimeMillis();
        log.info("耗时：{}",end-start);

        HashMap<String, Object> returnMap = new HashMap<>();
        returnMap.put(BaseDto.LIST,companyNames);
        return CommonResult.success(returnMap);
    }

    @Override
    public CommonResult<Object> procurementName(BaseDto dto) {
        long start = System.currentTimeMillis();
        LambdaEsQueryWrapper<ProcurementName> queryWrapper = new LambdaEsQueryWrapper<>();
        queryWrapper.match(ProcurementName::getProcurementUnit,dto.getKey()).size(6).sortByScore();
        List<ProcurementName> procurementNames = procurementMapper.selectList(queryWrapper);
        long end = System.currentTimeMillis();
        log.info("耗时：{}",end-start);

        HashMap<String, Object> returnMap = new HashMap<>();
        returnMap.put(BaseDto.LIST,procurementNames);
        return CommonResult.success(returnMap);
    }

    @Override
    public CommonResult<Object> getProcurementList(ProcurementDto dto) throws IOException {
        log.info("查询语句开始");
        long start = System.currentTimeMillis();

        SearchRequest searchRequest = new SearchRequest("tender_summary");
        //查询语句
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        searchSourceBuilder.size(0);
        //筛选参数
        BoolQueryBuilder boolQueryBuilder = new BoolQueryBuilder();
        if (dto.getCityList() != null && !dto.getCityList().isEmpty()){
            boolQueryBuilder.must(QueryBuilders.termsQuery("cityId",dto.getCityList()));
        }
        if (dto.getStartDateTime() != null && dto.getEndDateTime() != null){
            boolQueryBuilder.must(QueryBuilders.rangeQuery("renderDate").gte(dto.getStartDateTime()).lte(dto.getEndDateTime()));
        }
        if (dto.getProjectType() != null && !dto.getProjectType().isEmpty()){
            String regexp = StringUtils.join(dto.getProjectType(),"|");
            boolQueryBuilder.must(QueryBuilders.regexpQuery("projectClassification",".*(" + regexp + ").*"));
        }
        if (StringUtils.isNotBlank(dto.getKey())){
            boolQueryBuilder.must(QueryBuilders.matchQuery("procurementUnit",dto.getKey()));
        }
        searchSourceBuilder.query(boolQueryBuilder);

        Map<String, String> path = new HashMap<>();
        path.put("totalSumMoney","sumMoney");
        //聚合条件
        TermsAggregationBuilder aggregationBuilder = AggregationBuilders.terms("group_by_procurement_unit")
                .field("procurementUnitId")
                .size(10000)
                .order(BucketOrder.aggregation("lastRenderDate",false))
                .subAggregation(AggregationBuilders.sum("sumMoney").field("sumMoney"))
                .subAggregation(AggregationBuilders.max("lastRenderDate").field("lastRenderDate"))
                .subAggregation(AggregationBuilders.sum("tenderSize").field("tenderSize"));
        //筛选
        String scripMoney = "params.totalSumMoney != null ";
        boolean flag = false;
        if (dto.getMinMoney() != null){
            flag = true;
            scripMoney += "&& params.totalSumMoney  >= " + dto.getMinMoney();
        }
        if (dto.getMaxMoney() != null){
            flag = true;
            scripMoney += "&& params.totalSumMoney  <= " + dto.getMaxMoney();
        }
        if (flag){
            aggregationBuilder.subAggregation(PipelineAggregatorBuilders.bucketSelector("filter_by_sumMoney",path, Script.parse(scripMoney)));
        }
        //聚合条件
        searchSourceBuilder.aggregation(aggregationBuilder);

        // 执行查询
        searchRequest.source(searchSourceBuilder);
        long overBuilder = System.currentTimeMillis();
        log.info("请求参数包装完成：耗时{}",overBuilder-start);

        //请求查询

        SearchResponse searchResponse = tenderSummaryMapper.search(searchRequest, RequestOptions.DEFAULT);

        long overEs = System.currentTimeMillis();
        log.info("ES查询完成：耗时{}",overEs - overBuilder);
        // 处理查询结果
        Aggregations aggregations = searchResponse.getAggregations();
        Terms procurementUnitAgg = aggregations.get("group_by_procurement_unit");

        log.info("桶数量，{}",procurementUnitAgg.getBuckets().size());
        DecimalFormat decimalFormat = new DecimalFormat("0.00");
        DecimalFormat singleFormat = new DecimalFormat("0");

        List<ProcurementVo> tenderSums = new ArrayList<>();
        //循环处理
        for (Terms.Bucket bucket : procurementUnitAgg.getBuckets()) {
            ProcurementVo tenderSum = new ProcurementVo();

            Sum sumMoney1 = bucket.getAggregations().get("sumMoney");
            String sumMoney = decimalFormat.format(sumMoney1.getValue());

            Sum sumTenderSize = bucket.getAggregations().get("tenderSize");
            String tenderSize = singleFormat.format(sumTenderSize.getValue());

            tenderSum.setId(Integer.parseInt(bucket.getKeyAsString()));
            tenderSum.setSumMoney(sumMoney);
            tenderSum.setTenderSize(tenderSize);
            tenderSums.add(tenderSum);
        }
        long overBean = System.currentTimeMillis();
        log.info("解析完成，数量：{}，耗时：{}",tenderSums.size(),overBean-overEs);

        //从mysql中查询符合条件的数组，按照id进行获取并根据最新时间排序
        List<Integer> idList = tenderSums.stream().map(ProcurementVo::getId).collect(Collectors.toList());
        dto.setIdList(idList);
        List<ProcurementVo> voList = tenderInfoMapper.getProcurementVoBatchById(dto);
        long overMysql = System.currentTimeMillis();
        log.info("MySQL查询完成，数量：{}，耗时：{}",voList.size(),overMysql-overBean);
        //给列表赋值
        for (ProcurementVo vo : voList) {
            for (ProcurementVo sumInfo : tenderSums){
                if (vo.getId().equals(sumInfo.getId())){
                    vo.setSumMoney(sumInfo.getSumMoney());
                    vo.setTenderSize(sumInfo.getTenderSize());
                }
            }
        }
        Map<String, Object> returnMap = new HashMap<>();
        returnMap.put(BaseDto.LIST,voList);
        returnMap.put(BaseDto.TOTAL,idList.size());
        returnMap.put(BaseDto.PAGE,BaseDto.calculationPages(dto.getSize(),idList.size()));

        log.info("返回数据处理完成，总耗时：{}",System.currentTimeMillis()-start);

        return CommonResult.success(returnMap);
    }
}
